package com.crazymaker.springcloud.websocket.session;

import com.crazymaker.push.platform.contract.util.MsgUtils;
import com.crazymaker.springcloud.common.dto.UserDTO;
import com.crazymaker.springcloud.common.exception.BusinessException;
import com.crazymaker.springcloud.websocket.processer.MsgProcesser;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 实现服务器Socket Session会话
 * Created by 尼恩 @ 疯狂创客圈
 */
@Data
@Slf4j
public class ServerSession {


    public static final AttributeKey<String> KEY_USER_ID =
            AttributeKey.valueOf("key_user_id");

    public static final AttributeKey<ServerSession> SESSION_KEY =
            AttributeKey.valueOf("SESSION_KEY");


    /**
     * 用户实现服务端会话管理的核心
     */
    //通道
    private Channel channel;
    //用户
    private UserDTO user;


    //session唯一标示
    private String sessionId;

    private String group;

    //登录状态
    private volatile boolean isLogin = false;
    private volatile boolean isClose = false;

    /**
     * session中存储的session 变量属性值
     */
    private Map<String, Object> map = new HashMap<String, Object>();

    public ServerSession(Channel channel) {
        this.channel = channel;
    }


    public boolean bindChannel() {
        this.sessionId = buildSessionId();
        log.info(" ServerSession 绑定会话 " + channel.remoteAddress());
        channel.attr(ServerSession.SESSION_KEY).set(this);
        return true;
    }

    public boolean unbindChannel() {
        channel.attr(ServerSession.SESSION_KEY).set(null);
        return true;
    }

    //反向导航
    public static ServerSession getSession(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        return channel.attr(ServerSession.SESSION_KEY).get();
    }

    //反向导航
    public static ServerSession getSession(Channel channel) {
        return channel.attr(ServerSession.SESSION_KEY).get();
    }


    public String getId() {
        return sessionId;
    }

    private String buildSessionId() {
//        String uuid = UUID.randomUUID().toString();
//        return uuid.replaceAll("-", "");
        if (null == user) {
            throw BusinessException.builder().errMsg("用户信息为空").build();
        }
        return MsgUtils.getSessionId(user.getUsername(),user.getAppId());

    }

    public synchronized void set(String key, Object value) {
        map.put(key, value);
    }


    public synchronized <T> T get(String key) {
        return (T) map.get(key);
    }


    public boolean isValid() {
        return getUser() != null ? true : false;
    }


    /*  //关闭连接
      public synchronized void close() {
          ChannelFuture future = channel.close();
          future.addListener(new ChannelFutureListener() {
              @Override
              public void operationComplete(ChannelFuture future) throws Exception {
                  if (!future.isSuccess()) {
                      log.error("CHANNEL_CLOSED error ");
                  }
              }
          });
      }
      //关闭连接
      public static void closeSession(ChannelHandlerContext ctx) {
          ServerSession session =
                  ctx.channel().attr(ServerSession.SESSION_KEY).get();

          if (null != session && session.isValid()) {
              session.close();
              SessionMap.inst().removeSession(session.getId());
          }
      }
  */
    public UserDTO getUser() {
        return user;
    }

    public void setUser(UserDTO user) {
        this.user = user;
    }


    public void processIdle() {


        String echo = MsgProcesser.getSingleton().onIdleTooLong(this);
        /**
         * 关闭连接， 关闭前发送一条通知消息
         */

        SessionManager.getSingleton().closeSessionAfterAck(this, echo);


    }

    public void closeChannel() {
        if (null == channel) {
            return;
        }
        channel.close();
    }

    public synchronized void close() {
        if (isClose) return;
        ChannelFuture sendFuture = channel.close();
        sendFuture.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) {
                log.debug("closeSession finished,Nickname:{}", user.getNickname());
            }
        });
        isClose = true;
    }
}
